package top.cardone.template.support.impl;

import com.google.common.collect.Maps;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import top.cardone.core.CodeException;
import top.cardone.template.support.TemplateSupport;

import java.io.File;
import java.util.Map;
import java.util.Objects;

/**
 * @author yao hai tao
 */
@lombok.extern.log4j.Log4j2
public class TemplateSupportImpl implements TemplateSupport {
    /**
     * 消息格式化映射
     */
    @lombok.Getter
    @lombok.Setter
    private Map<String, Configuration> configurationMap = Maps.newConcurrentMap();
    /**
     * freemarker.template.Configuratio
     */
    @lombok.Getter
    @lombok.Setter
    private String defaultConfigurationKey = "configuration1";
    /**
     * 显示model
     */
    @lombok.Getter
    @lombok.Setter
    private Boolean showModel = true;

    /**
     * 显示解析模板后字符串
     */
    @lombok.Getter
    @lombok.Setter
    private Boolean showProcessTemplateIntoString = true;

    /**
     * 显示模板字符串
     */
    @lombok.Getter
    @lombok.Setter
    private Boolean showTemplateString = false;

    /**
     * 模板映射
     */
    private Map<String, Template> templateMap = Maps.newConcurrentMap();

    @Override
    public String process(final String filePath, final Object model) {
        return this.process(this.defaultConfigurationKey, filePath, model);
    }

    @Override
    public String toString(String configurationKey, String filePath) {
        if (CollectionUtils.isEmpty(configurationMap) || !configurationMap.containsKey(configurationKey)) {
            return StringUtils.EMPTY;
        }

        Configuration configuration = configurationMap.get(configurationKey);

        try {
            Object object = configuration.getTemplateLoader().findTemplateSource(filePath);

            if (object == null) {
                throw new CodeException("00000021", "文件不存在");
            }

            File file = new File(object.toString());

            if (!file.exists()) {
                throw new CodeException("00000021", "文件不存在");
            }

            return FileUtils.readFileToString(file);
        } catch (java.io.IOException e) {
            throw new CodeException("00000000", e);
        }
    }

    @Override
    public String toString(String filePath) {
        return this.toString(this.defaultConfigurationKey, filePath);
    }

    @Override
    public String process(String configurationKey, String filePath, Object model) {
        if (CollectionUtils.isEmpty(configurationMap) || !configurationMap.containsKey(configurationKey)) {
            return StringUtils.EMPTY;
        }

        Configuration configuration = configurationMap.get(configurationKey);

        try {
            final Template template = configuration.getTemplate(filePath);

            if (BooleanUtils.isTrue(this.showTemplateString)) {
                log.warn(template.toString());
            }

            String str;

            try (java.io.StringWriter writer = new java.io.StringWriter()) {
                template.process(model, writer);

                str = writer.toString();
            }

            if (BooleanUtils.isTrue(this.showProcessTemplateIntoString)) {
                log.warn(str);
            }

            if (BooleanUtils.isTrue(this.showModel)) {
                log.warn(Objects.toString(model));
            }

            return StringUtils.defaultIfBlank(str, StringUtils.EMPTY);
        } catch (freemarker.template.TemplateException | java.io.IOException e) {
            throw new CodeException("00000000", e);
        }
    }

    @Override
    public String processString(final String templateString, final Object model) {
        return processString(this.defaultConfigurationKey, templateString, model);
    }

    @Override
    public String processString(String configurationKey, String templateString, Object model) {
        if (CollectionUtils.isEmpty(configurationMap) || !configurationMap.containsKey(configurationKey)) {
            return StringUtils.EMPTY;
        }

        if (StringUtils.isBlank(templateString)) {
            return StringUtils.EMPTY;
        }

        if (BooleanUtils.isTrue(this.showTemplateString)) {
            log.warn(templateString);
        }

        try (java.io.StringWriter writer = new java.io.StringWriter()) {
            final String name = DigestUtils.md5Hex(templateString);

            Template template = templateMap.get(name);

            if (template == null) {
                try (java.io.Reader reader = new java.io.StringReader(templateString)) {
                    Configuration configuration = configurationMap.get(configurationKey);

                    template = new Template(name, reader, configuration);

                    templateMap.put(name, template);
                }
            }

            template.process(model, writer);

            String str = writer.toString();

            if (BooleanUtils.isTrue(this.showProcessTemplateIntoString)) {
                log.warn(str);
            }

            if (BooleanUtils.isTrue(this.showModel)) {
                log.warn(Objects.toString(model));
            }

            return str;
        } catch (Exception e) {
            throw new CodeException("00000000", e);
        }
    }
}